package net.ikenway.springboot.demo.Service.Implement;

import net.ikenway.springboot.demo.Dao.AddressRepository;
import net.ikenway.springboot.demo.Dao.OrderRepository;
import net.ikenway.springboot.demo.Dao.ProductRepository;
import net.ikenway.springboot.demo.Dao.UserRepository;
import net.ikenway.springboot.demo.Model.Dto.OrderDto;
import net.ikenway.springboot.demo.Model.Dto.OrderSubDto;
import net.ikenway.springboot.demo.Model.Entity.Order;
import net.ikenway.springboot.demo.Model.Entity.OrderSub;
import net.ikenway.springboot.demo.Model.Entity.Product;
import net.ikenway.springboot.demo.Model.Entity.User;
import net.ikenway.springboot.demo.Service.Interface.OrderServiceIntf;
import net.ikenway.springboot.demo.Utils.MapperUtil;
import net.ikenway.springboot.demo.Utils.SpringContextUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.persistence.EntityNotFoundException;
import javax.transaction.Transactional;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Supplier;

/**
 * @author MasterKenway <zk@ikenway.net>
 * @Description
 * @date Created Date 12/17/2020
 */
@Service
public class OrderServiceImpl implements OrderServiceIntf {
    private final ProductRepository productRepository;
    private final AddressRepository addressRepository;
    private final MapperUtil mapperUtil;

    private final OrderRepository orderRepository;

    private final UserRepository userRepository;


    @Autowired
    public OrderServiceImpl(OrderRepository orderRepository,
                            UserRepository userRepository,
                            ProductRepository productRepository,
                            AddressRepository addressRepository,
                            MapperUtil mapperUtil) {
        this.orderRepository = orderRepository;
        this.userRepository = userRepository;
        this.productRepository = productRepository;
        this.addressRepository = addressRepository;
        this.mapperUtil = mapperUtil;
    }

    @Override
    public List<OrderDto> findAll() {
        List<Order> orders = orderRepository.findAll();
        List<OrderDto> orderDtos = mapperUtil.mapList(orders, OrderDto.class);
        for (int i = 0; i < orders.size(); i++) {
            orderDtos.get(i).setOrderSubDtos(mapperUtil.mapList(orders.get(i).getOrderSubs(), OrderSubDto.class));
        }
        return orderDtos;
    }

    @Override
    public List<OrderDto> findAllByCurrentUser() {
        User currentUser = SpringContextUtil.getCurrentUser();
        List<Order> orders = currentUser.getOrders();
        List<OrderDto> orderDtos = mapperUtil.mapList(orders, OrderDto.class);
        for (int i = 0; i < orderDtos.size(); i++) {
            orderDtos.get(i).setOrderSubDtos(mapperUtil.mapList(orders.get(i).getOrderSubs(), OrderSubDto.class));
        }
        return orderDtos;
    }

    @Override
    public List<OrderDto> findByStatus(String status) throws Exception {
        Long userId = SpringContextUtil.getCurrentUser().getUserId();
        switch (status) {
            case "TOPAY":
                return mapperUtil.mapList(orderRepository.findByStatusAndUserUserId(Order.Status.TOPAY, userId), OrderDto.class);
            case "PAYED":
                return mapperUtil.mapList(orderRepository.findByStatusAndUserUserId(Order.Status.PAYED, userId), OrderDto.class);
            case "CANCELING":
                return mapperUtil.mapList(orderRepository.findByStatusAndUserUserId(Order.Status.CANCELING, userId), OrderDto.class);
            case "CANCELLED":
                return mapperUtil.mapList(orderRepository.findByStatusAndUserUserId(Order.Status.CANCELLED, userId), OrderDto.class);
            case "FINISHED":
                return mapperUtil.mapList(orderRepository.findByStatusAndUserUserId(Order.Status.FINISHED, userId), OrderDto.class);
            default:
                throw new Exception("查询条件不合法");
        }
    }

    @Override
    public Order create(OrderDto orderDto) throws Throwable {
        User user = SpringContextUtil.getCurrentUser();
        Order order = mapperUtil.map(orderDto, Order.class);
        order.setOrderSubs(mapperUtil.mapList(orderDto.getOrderSubDtos(), OrderSub.class));
        BigDecimal tmp = new BigDecimal("0");
        for (int i = 0; i < orderDto.getOrderSubDtos().size(); i++) {
            OrderSub orderSub = order.getOrderSubs().get(i);
            OrderSubDto orderSubDto = orderDto.getOrderSubDtos().get(i);

            Product product = productRepository.findById(orderSubDto.getProductId()).orElseThrow(new Supplier<Throwable>() {
                @Override
                public Throwable get() {
                    return new EntityNotFoundException("商品不存在");
                }
            });
            product.setSellCounter(product.getSellCounter() + 1);
            productRepository.save(product);

            BigDecimal productPrice = orderSub.getScale() == OrderSub.Scale.MEDIUM ? product.getMediumPrice() : product.getLargePrice();
            orderSub.setActualPrice(productPrice.multiply(product.getDisCount()));
            orderSub.setDisCount(product.getDisCount());

            orderSub.setProduct(product);

            tmp = tmp.add(orderSub.getActualPrice());
        }
        order.setTotalPrice(tmp);

        order.setAddress(addressRepository.findByAddressIdAndUserUserId(orderDto.getAddressId(), SpringContextUtil.getCurrentUser().getUserId()));
        if (order.getAddress() == null) throw new EntityNotFoundException("地址不存在");

        order = orderRepository.save(order);

        user.getOrders().add(order);
        userRepository.save(user);
        return order;
    }

    @Override
    public void toPayed(Long orderId) throws Exception {
        Order order = exitsOrNot(orderId);
        User user = SpringContextUtil.getCurrentUser();
        if (!order.getUser().getUserId().equals(user.getUserId()))
            throw new EntityNotFoundException();

        if (order.getStatus() == Order.Status.CANCELLED
                || order.getStatus() == Order.Status.CANCELING)
            throw new Exception("订单已经被取消，无法完成支付");
        else if (order.getStatus() == Order.Status.FINISHED)
            throw new Exception("订单已经完成，无法支付");
        else if (order.getStatus() == Order.Status.PAYED)
            throw new Exception("订单已经支付成功，不可重复支付");
        order.setStatus(Order.Status.PAYED);
        order.setPurchaseTime(new Timestamp(System.currentTimeMillis()));
        orderRepository.save(order);
    }

    @Override
    public String cancel(Long orderId) throws Exception {
        Order order = exitsOrNot(orderId);
        if (!order.getUser().getUserId().equals(SpringContextUtil.getCurrentUser().getUserId()))
            throw new EntityNotFoundException();

        if (order.getStatus() == Order.Status.CANCELLED)
            throw new Exception("订单已被取消，不可重复取消");
        else if (order.getStatus() == Order.Status.FINISHED)
            throw new Exception("订单已完成，无法被取消");

        String msg;
        if (order.getStatus() == Order.Status.TOPAY) {
            order.setStatus(Order.Status.CANCELLED);
            msg = "订单已被取消";
        } else {
            order.setStatus(Order.Status.CANCELING);
            msg = "订单取消申请已经提交，请耐心等待审核";

        }
        orderRepository.save(order);
        return msg;
    }

    @Transactional
    @Override
    public void toCancelled(List<Long> orderIds) throws Exception {
        if (orderIds.isEmpty()) throw new Exception("数组不能为空");

        List<Order> orders = new ArrayList<>();
        for (Long orderId : orderIds) {
            Order order = exitsOrNot(orderId);
            toCancelledValidate(order);
            order.setStatus(Order.Status.CANCELLED);
            orders.add(order);
        }
        orderRepository.saveAll(orders);
    }


    public void toCancelledValidate(Order order) throws Exception {
        if (order.getStatus() == Order.Status.CANCELLED)
            throw new Exception("订单已被取消，不可重复取消");
        else if (order.getStatus() == Order.Status.FINISHED)
            throw new Exception("订单已完成，无法被取消");
        else if (order.getStatus() == Order.Status.TOPAY
                || order.getStatus() == Order.Status.CANCELING)
            throw new Exception("无权限进行操作");
    }


    @Transactional
    @Override
    public void finish(List<Long> orderIds) throws Exception {
        for (Long orderId : orderIds) {
            Order order = exitsOrNot(orderId);
            if (order.getStatus() != Order.Status.PAYED)
                throw new Exception("流程不合法");
            order.setStatus(Order.Status.FINISHED);
            orderRepository.save(order);
        }
    }

    @Override
    public Order exitsOrNot(Long orderId) throws EntityNotFoundException {
        return orderRepository.findById(orderId).orElseThrow(EntityNotFoundException::new);
    }

}
